package com.corticon.dialogs.web.designer;

import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.Date;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

import com.corticon.dialogs.dao.UserGroupDAO;
import com.corticon.dialogs.model.UserGroup;
import com.corticon.dialogs.model.User;
import com.corticon.dialogs.util.Pager;
import com.corticon.dialogs.util.CommonSupport;
import com.corticon.dialogs.validation.GenericHibernateValidator;
import com.corticon.dialogs.validation.ValidationMessageFormatter;
import com.corticon.dialogs.web.BaseController;

/**
 * @author Lifan Yang
 * @since 2008-09-20
 */
@Controller
@SessionAttributes({"userGroup"})
public class GroupController extends BaseController {

    private final String LIST_VIEW_NAME = "designer.group.list";
    @Resource
    private UserGroupDAO userGroupDAO;    // Validators
    @Resource
    private CommonSupport commonSupport;

    private CreateValidator createValidator;
    private EditValidator editValidator;

    // ********** Validators ********** //
    private class CreateValidator extends GenericHibernateValidator<UserGroup> {

        public CreateValidator(ValidationMessageFormatter validationMessageFormatter) {
            super.validationMessageFormatter = validationMessageFormatter;
        }

        @Override
        protected void complexValidate(Object object, Errors errors) {
            UserGroup group = (UserGroup) object;
            UserGroup oldGroup = userGroupDAO.findById(group.getName());
            if (oldGroup != null) {
                errors.rejectValue("name", "group.name.existed", "The name is existed.");
            }

            simpleStringValidate(errors, group.getName(), "name", "validate.group.name.invalid");
        }
    }

    private class EditValidator extends GenericHibernateValidator<UserGroup> {

        public EditValidator(ValidationMessageFormatter validationMessageFormatter) {
            super.validationMessageFormatter = validationMessageFormatter;
        }
    }

    /**
     * Instantiate the validators after the construct method.
     */
    @PostConstruct
    private void buildValidators() {
        createValidator = new CreateValidator(validationMessageFormatter);
        editValidator = new EditValidator(validationMessageFormatter);
    }

    @Transactional(readOnly = true)
    @RequestMapping(value = VIEW_REQUEST, method = RequestMethod.GET)
    public String view(@RequestParam String groupname, HttpServletRequest request) {
        UserGroup group = userGroupDAO.findById(groupname);
        request.setAttribute("group", group);
        readMessages(defaultMessageKeys, request);
        return getViewNameByRequestURI(request);
    }

    @RequestMapping(value = CREATE_REQUEST, method = RequestMethod.GET)
    public String getCreate(ModelMap model, HttpServletRequest request) {

        UserGroup group = new UserGroup();

        model.addAttribute(group);

        request.setAttribute(OPERATION_KEY, CREATE_REQUEST);

        request.setAttribute(DEFAULT_MESSAGE_KEY, getMessage("common.action.prompt"));

        readMessages(defaultMessageKeys, request);

        return getViewNameByRequestURI(request);
    }

    @Transactional
    @RequestMapping(value = CREATE_REQUEST, method = RequestMethod.POST)
    public String postCreate(@RequestParam String submitAction, @ModelAttribute UserGroup group, Errors errors,
                             HttpServletRequest request, SessionStatus sessionStatus) throws UnsupportedEncodingException {

        request.setAttribute(OPERATION_KEY, CREATE_REQUEST);

        // Validate the form object.
        Map<String, List<String>> errorsMessages = createValidator.invokeValidate(group, errors,
                request.getLocale());
        request.setAttribute("errors", errorsMessages);

        if (errors.hasErrors()) {
            return getViewNameByRequestURI(request);
        }

        // Update modified info.
        User adminUser = commonSupport.findCurrentUser();
        group.setModifiedBy(adminUser);
        group.setModifiedOn(new Date());

        userGroupDAO.save(group);

        sessionStatus.setComplete();

        String[] args = {group.getName()};
        addMessages("message=group.create.Success", request, messageSource, args);

        return redirectBySubmitAction(submitAction, "groupname=" + group.getName());
    }

    @Transactional(readOnly = true)
    @RequestMapping(value = EDIT_REQUEST, method = RequestMethod.GET)
    public String getEdit(@RequestParam String groupname, ModelMap model, HttpServletRequest request) {

        UserGroup group = userGroupDAO.findById(groupname);

        if (group == null) {
            addMessages("message=group.notExisted", request, messageSource, defaultMessageKeys);
            return redirectPrefix + LIST_REQUEST + requestSuffix;
        }

        model.addAttribute(group);

        request.setAttribute(OPERATION_KEY, EDIT_REQUEST);

        request.setAttribute(DEFAULT_MESSAGE_KEY, getMessage("common.action.prompt"));

        readMessages(defaultMessageKeys, request);

        return getViewNameByRequestURI(request);
    }

    @Transactional
    @RequestMapping(value = EDIT_REQUEST, method = RequestMethod.POST)
    public String postEdit(@RequestParam String submitAction, @ModelAttribute UserGroup group,
                           Errors errors, HttpServletRequest request, SessionStatus sessionStatus) {

        request.setAttribute(OPERATION_KEY, EDIT_REQUEST);

        // Validate the form object.
        Map<String, List<String>> errorsMessages = editValidator.invokeValidate(group, errors, request.getLocale());
        request.setAttribute("errors", errorsMessages);

        if (errors.hasErrors()) {
            return getViewNameByRequestURI(request);
        }

        // Update modified info.
        User adminUser = commonSupport.findCurrentUser();
        group.setModifiedBy(adminUser);
        group.setModifiedOn(new Date());

        userGroupDAO.update(group);

        sessionStatus.setComplete();

        String[] args = {group.getName()};
        addMessages("message=group.edit.Success", request, messageSource, args);

        return redirectBySubmitAction(submitAction, "groupname=" + group.getName());
    }

    @Transactional(readOnly = true)
    @RequestMapping(value = "list", method = RequestMethod.GET)
    public String list(@RequestParam(required = false) Integer page, HttpServletRequest request) {

        Pager pager = constructPager(page, request);

        long count = userGroupDAO.getCountAll();
        pager.setNumOfRecords(count);
        pager = setPagerSort(pager, "name", request);
        request.setAttribute("pager", pager);

        List<UserGroup> groups = userGroupDAO.getPageOfDataAll(pager);
        request.setAttribute("groups", groups);

        if (groups != null && groups.size() > 0) {
            request.setAttribute("foundMessage", getMessage(String.valueOf(pager.getNumOfRecords()), publicFoundMessage));
        } else {
            request.setAttribute("foundMessage", getMessage("", publicNotFoundMessage));
        }
        readMessages(defaultMessageKeys, request);

        return getViewNameByRequestURI(request);
    }

    @RequestMapping(method = RequestMethod.GET)
    public String search(@RequestParam(required = false) Integer page, @RequestParam(required = false) String keywords,
                         HttpServletRequest request) {

        Pager pager = constructPager(page, request);
        pager.setNumOfRecords(userGroupDAO.getSearchCount(keywords));
        pager = setPagerSort(pager, "name", request);
        request.setAttribute(PAGER_NAME, pager);

        List<UserGroup> groups = userGroupDAO.search(keywords, pager);
        request.setAttribute("groups", groups);
        if (groups != null && groups.size() > 0) {
            request.setAttribute("foundMessage", getMessage(String.valueOf(pager.getNumOfRecords()), publicFoundMessage));
        } else {
            request.setAttribute("foundMessage", getMessage("", publicNotFoundMessage));
        }
        return LIST_VIEW_NAME;
    }

    // ********** Accessors ********** //
    public void setUserGroupDAO(UserGroupDAO userGroupDAO) {
        this.userGroupDAO = userGroupDAO;
    }
}
